package track_formats

import (
	"fmt"
	"time"

	"github.com/pion/rtp"
	"gogs.smarteye.com/servere/gobvrtp/encoder"
	"gogs.smarteye.com/servere/gobvrtp/track"
)

type OpusTrack struct {
	AudioTrack

	IsStereo bool

	encoder *encoder.AudioEncoder
	decoder *encoder.AudioDecoder
}

func NewOpusTrack() *OpusTrack {
	c := &OpusTrack{}

	param := c.CtlParma()
	param.SetPayloadType(111)
	param.SetCodec(track.CodecIdOPUS)
	param.SetOnReadRTPFunc(c.onRTP)
	param.SetClockRate(48000)
	param.SetChannel(2)

	return c
}

func (c *OpusTrack) UnmarshalFormat(ctx *track.FormatContext) error {
	_ = c.AudioTrack.UnmarshalFormat(ctx)

	param := c.CtlParma()
	param.SetPayloadType(ctx.GetRtpMap().PayloadType)

	sampleRate := ctx.GetRtpMap().ClockRate
	if sampleRate != 48000 {
		return fmt.Errorf("invalid sample rate: %d", sampleRate)
	}

	channelCount := ctx.GetRtpMap().Parameters
	if channelCount != 2 {
		return fmt.Errorf("invalid channel count: %d", channelCount)
	}

	for key, val := range ctx.GetFMTP().KV {
		if key == "sprop-stereo" {
			c.IsStereo = val == "1"
		}
	}

	return nil
}

// RTPMap implements Format.
func (c *OpusTrack) RTPMap() string {
	// RFC7587: The RTP clock rate in "a=rtpmap" MUST be 48000, and the
	// number of channels MUST be 2.
	return "opus/48000/2"
}

// FMTP implements Format.
func (c *OpusTrack) FMTP() map[string]string {
	fmtp := map[string]string{
		"sprop-stereo": func() string {
			if c.IsStereo {
				return "1"
			}
			return "0"
		}(),
	}
	return fmtp
}

func (c *OpusTrack) WritePacket(t time.Time, data []byte) error {
	param := c.CtlParma()

	if c.encoder == nil {
		// 初始化编码器
		e := &encoder.AudioEncoder{
			PayloadType:           c.PayloadType(),
			SSRC:                  ToPtr(c.SSRC()),
			InitialSequenceNumber: ToPtr(param.InitialSequenceNumber),
			PayloadMaxSize:        param.PayloadMaxSize,
		}
		_ = e.Init()
		c.encoder = e
	}

	packet, err := c.encoder.Encode(data)
	if err != nil {
		return err
	}

	timestamp, _ := c.CtlParma().RtpTimeEncode(t)
	packet.Timestamp = timestamp

	if err = c.WriteRTP(packet); err != nil {
		return err
	}

	return nil
}

func (c *OpusTrack) onRTP(_ track.Track, pkt *rtp.Packet) {
	packets, _ := c.Detector(pkt)

	if c.decoder == nil {
		decoder := &encoder.AudioDecoder{}
		_ = decoder.Init()
		c.decoder = decoder
	}

	for _, packet := range packets {
		if data, err := c.decoder.Decode(packet); err == nil {
			c.onFrame(packet, data)
		}
	}
}

func init() {
	RegisterTrack(track.CodecIdOPUS, func() track.Track {
		return NewOpusTrack()
	})
}
